// 首次编译模版，接受一个参数，vue的实例
// compile方法开始编译模版
// compileText处理文本节点
// compileElement处理元素节点

class Compiler {
    constructor(vm) {
        this.vm = vm;
        this.el = vm.$el;
        // 开始编译模版
        this.compile(this.el);
    }

    compile(el) {
        const childNodes = el.childNodes;
        Array.from(childNodes).forEach(node => {
            if (this.isTextNode(node)) {
                // 处理文本节点
                this.compileText(node);
            } else if (this.isElementNode(node)) {
                // 处理元素节点
                this.compileElement(node);
            }

            // 递归循环处理每个元素的子元素
            if (node.childNodes && node.childNodes.length !== 0) this.compile(node);
        })
    }

    // 编译文本节点
    compileText(node) {
        // 正则表达式匹配差值表达式中的key值
        const reg = /\{\{(.+?)\}\}/;
        const value = node.textContent;
        if (reg.test(value)) {
            const key = RegExp.$1.trim();
            node.textContent = this.vm[key];
            // 给每一个差值表达式视图添加一个观察者，等待后续如果对应的数据更改，则同步更新view
            new Watcher(this.vm, key, (newValue) => {
                node.textContent = newValue;
            })
        } 
    }

    // 编译元素节点，处理指令
    compileElement(node) {
        // 遍历所有节点的属性
        Array.from(node.attributes).forEach(attr => {
            const attrName = attr.name;
            if (this.isDirective(attrName)) {
                const key = attrName.substr(2);
                if (key.startsWith('on')) {
                    this.eventHandler(node, key, attr.value);
                } else {
                    this.updater(node, key, attr.value);
                }
            }
        })
    }

    /**
     * 
     * @param {*} node 元素节点
     * @param {*} attrKey 属性名称，如 v-text中的text
     * @param {*} key 对应data中挂在的属性值键名
     */
     updater(node, attrName, key) {
        const updateFn = this[`${attrName}Updater`];
        const value  = this.vm[key]
        updateFn && updateFn.call(this, node, value, key);
    }

    // 处理v-text指令
    textUpdater(node, value, key) {
        node.textContent = value;

         // 创建watcher，当数据更新时，视图更新
        new Watcher(this.vm, key, (newValue) => {
            node.textContent = newValue;
        })
    }

    // 处理v-model指令
    modelUpdater(node, value, key) {
        node.value = value;

        // 创建watcher，当数据更新时，视图更新
        new Watcher(this.vm, key, (newValue) => {
            node.value = newValue;
        })

        // 双向绑定
        node.addEventListener('input', () => {
            this.vm[key] = node.value;
        })
    }

    // 处理v-html指令
    htmlUpdater(node, value, key) {
        node.innerHTML = value;

        // 创建watcher，当数据更新时，视图更新
        new Watcher(this.vm, key, (newValue) => {
            node.innerHTML = newValue;
        })
    }

    // 处理v-on指令
    eventHandler(node, value, key) {
        const eventName = value.substr(3);
        node.addEventListener(eventName, this.vm[key])
    }

    // 判断是否是指令
    isDirective(attrName) {
        return attrName.startsWith('v-')
    }

    // 判断是否是文本节点
    isTextNode(node) {
        return node.nodeType === 3;
    }

    // 判断是否是元素节点
    isElementNode(node) {
        return node.nodeType === 1;
    }
}